#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

#include <serial.h>
#include <command.h>

static int uart_fd;
pthread_mutex_t uart_lock = PTHREAD_MUTEX_INITIALIZER;

/*
 *  函数名：uart_receive_thread
 *  功能说明：串口接收线程，接收串口发送的指令
 *  参数：arg - 线程参数
 *  返回值：void* - 线程返回值
 *  日期：2025年3月
 */
void *uart_receive_thread(void *arg)
{
	char buf[BUF_SIZE];

	while(1)
	{
		ssize_t ret = read(uart_fd, buf, sizeof(buf) - 1);
		if(ret > 0)
		{
			buf[ret] = '\0';
			printf("Received: %s\n", buf);
			parse_command(buf);
		}
	}
	return NULL;
}


//设置串口
/* set_opt(fd,115200,8,'N',1) */
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
	struct termios newtio,oldtio;
	printf("set opt start!\n");
	if ( tcgetattr( fd,&oldtio) != 0) { 
		perror("SetupSerial 1");
		return -1;
	}
	
	bzero( &newtio, sizeof( newtio ) );
	newtio.c_cflag |= CLOCAL | CREAD; 
	newtio.c_cflag &= ~CSIZE; 

	newtio.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
	newtio.c_oflag  &= ~OPOST;   /*Output*/

	switch( nBits )
	{
	case 7:
		newtio.c_cflag |= CS7;
	break;
	case 8:
		newtio.c_cflag |= CS8;
	break;
	}

	switch( nEvent )
	{
	case 'O':
		newtio.c_cflag |= PARENB;
		newtio.c_cflag |= PARODD;
		newtio.c_iflag |= (INPCK | ISTRIP);
	break;
	case 'E': 
		newtio.c_iflag |= (INPCK | ISTRIP);
		newtio.c_cflag |= PARENB;
		newtio.c_cflag &= ~PARODD;
	break;
	case 'N': 
		newtio.c_cflag &= ~PARENB;
	break;
	}

	switch( nSpeed )
	{
	case 2400:
		cfsetispeed(&newtio, B2400);
		cfsetospeed(&newtio, B2400);
	break;
	case 4800:
		cfsetispeed(&newtio, B4800);
		cfsetospeed(&newtio, B4800);
	break;
	case 9600:
		cfsetispeed(&newtio, B9600);
		cfsetospeed(&newtio, B9600);
	break;
	case 115200:
		cfsetispeed(&newtio, B115200);
		cfsetospeed(&newtio, B115200);
	break;
	default:
		cfsetispeed(&newtio, B9600);
		cfsetospeed(&newtio, B9600);
	break;
	}
	
	if( nStop == 1 )
		newtio.c_cflag &= ~CSTOPB;
	else if ( nStop == 2 )
		newtio.c_cflag |= CSTOPB;
	
	newtio.c_cc[VMIN]  = 1;  /* 读数据时的最小字节数: 没读到这些数据我就不返回! */
	newtio.c_cc[VTIME] = 0; /* 等待第1个数据的时间: 
	                         * 比如VMIN设为10表示至少读到10个数据才返回,
	                         * 但是没有数据总不能一直等吧? 可以设置VTIME(单位是10秒)
	                         * 假设VTIME=1，表示: 
	                         *    10秒内一个数据都没有的话就返回
	                         *    如果10秒内至少读到了1个字节，那就继续等待，完全读到VMIN个数据再返回
	                         */

	tcflush(fd,TCIFLUSH);
	
	if((tcsetattr(fd,TCSANOW,&newtio))!=0)
	{
		perror("com set error");
		return -1;
	}
	printf("set done!\n");
	return 0;
}

//打开串口
int open_port(char *com)
{
	int fd;
	//fd = open(com, O_RDWR|O_NOCTTY|O_NDELAY);
	fd = open(com, O_RDWR|O_NOCTTY);
    if (-1 == fd){
		return(-1);
    }
	
	  if(fcntl(fd, F_SETFL, 0)<0) /* 设置串口为阻塞状态*/
	  {
			printf("fcntl failed!\n");
			return -1;
	  }
  
	  return fd;
}

int uart_init(char *device)
{
	int ret;
	uart_fd = open_port(device);
	if (uart_fd < 0)
	{
		printf("open %s err!\n", device);
		return -1;
	}
	ret = set_opt(uart_fd, 9600, 8, 'N', 1);
	if (ret)
	{
		printf("Set port err!\n");
		return -1;
	}
	return uart_fd;
}

int uart_send(char *data)
{
	pthread_mutex_lock(&uart_lock);
	printf("[Forklift] uart_send data:%s\n", data);
	int ret = write(uart_fd, data, strlen(data));
	pthread_mutex_unlock(&uart_lock);
	return ret;
}

void uart_clean(void)
{
	pthread_mutex_lock(&uart_lock);
	close(uart_fd);
	pthread_mutex_unlock(&uart_lock);
}